import {
  WSBridgeDatagramCategory,
  WSBridgeEventDatagram,
  WSBridgeUIInitDatagram,
} from "@common/meta";
import events from "@/ui/events";
import { toast } from "sonner";

Object.assign(window, { events });

const WS_MAX_TRY_COUNT = 3;

export class AppCore {
  ws?: WebSocket;

  private _wsTryCount = WS_MAX_TRY_COUNT;

  private _onWSMessage = (ev: MessageEvent) => {
    try {
      const {
        payload: { data, event, sender },
      } = JSON.parse(ev.data.toString()) as WSBridgeEventDatagram;
      events.Remote.Accept.emit({
        sender,
        data,
        eventName: event,
      });
    } catch (err) {
      console.error("received error:", err, ev.data);
    }
  };
  private _onWSOpen = () => {
    this._wsTryCount = WS_MAX_TRY_COUNT;
    this.initEvents();

    this.ws?.send(
      JSON.stringify({
        category: WSBridgeDatagramCategory.CORE_UI_INIT,
        payload: { name: "tony" },
      } as WSBridgeUIInitDatagram),
    );
  };
  private _onWSClose = () => {
    console.warn("ws closed, try to reconnect");
    setTimeout(() => {
      if (this._wsTryCount--) {
        this._initWebSocket();
      } else {
        alert("程序异常：主控连接失败");
      }
    }, 500);
  };
  private _onWSError = (err: unknown) => {
    console.error("ws error:", err);
  };

  private _initWebSocket() {
    const urlObj = new URL(location.toString());
    const ws = new WebSocket(
      `ws://${urlObj.hostname}:${urlObj.searchParams.get("port")}/ui`,
    );
    this.ws = ws;
    ws.onmessage = this._onWSMessage;
    ws.onopen = this._onWSOpen;
    ws.onclose = this._onWSClose;
    ws.onerror = this._onWSError;
  }

  constructor() {
    this._initWebSocket();
  }

  initEvents() {
    events.Remote.Invoke.on((params) => {
      const { eventName, data, receiverId } = params;
      this.ws?.send(
        JSON.stringify({
          category: WSBridgeDatagramCategory.CORE_EVENT,
          payload: {
            data,
            event: eventName,
            sender: "ui",
            receiverId,
          },
        } as WSBridgeEventDatagram),
      );
    });
    events.Global.App.Notify.on(({ category, message }) => {
      toast(`${category}：${message}`);
    });
  }
}
